﻿//by SymbolicComputation.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace SymbolicComputation
{
    public enum enumSideOfOperator { Left, Right, NotBinary }
    public class Miscellaneous
    {
        public static enumSideOfOperator SideOfEqualSign(SyntaxNode inNode)
        {
            SyntaxNode child = inNode;
            Boolean searching = true;
            while (searching == true)
            {
                if (child.Parent == null)
                {
                    return enumSideOfOperator.NotBinary;
                }
                if (child.Parent.Kind == SyntaxKind.EqualsExpression)
                {
                    return SideOfOperator(child);
                }
                child = child.Parent;
            }
            return enumSideOfOperator.NotBinary;
        }

        public static enumSideOfOperator SideOfOperator(SyntaxNode inNode)
        {
            if (Miscellaneous.IsBinary(inNode) == true)
            {
                if (inNode == inNode.Parent.ChildNodes().ToList()[0])
                {
                    return enumSideOfOperator.Left;
                }
                else
                {
                    return enumSideOfOperator.Right;
                }
            }
            else
            {
                return enumSideOfOperator.NotBinary;
            }
        }

        public static Boolean IsBinary(SyntaxNode syntaxNode)
        {
            Type type = syntaxNode.GetType();
            if (type.Name == "BinaryExpressionSyntax")
            {
                return true;
            }
            return false;
        }

        public static SyntaxNode CloneSyntaxNode(SyntaxNode inTree)
        {
            String str = inTree.ToString();
            return EquationToSyntaxNode(str);
        }

        public static SyntaxNode[] EquationsToSyntaxNodes(String[] inEquations)
        {
            return Functional.Maps.Map(inEquations, EquationToSyntaxNode); ;
        }

        public static SyntaxNode EquationToSyntaxNode(String inEquation)
        {
            SyntaxNode lOut = Syntax.ParseExpression(inEquation);
            return lOut;
        }

        public static Int32 SearchForEndForwards(String SearchMe, String inOperator, Int32 startLocation)
        {
            Int32 L;
            String subString;
            for (L = startLocation; L < SearchMe.Length; L++)
            {
                if (L + inOperator.Length > SearchMe.Length)
                {
                    //fail!
                }
                else
                {
                    subString = SearchMe.Substring(L, inOperator.Length);
                    if (inOperator == subString)
                    {
                        return L;
                    }
                }
            }
            return SearchMe.Length;
        }

        public static String ConvertToDoubleEqualSigns(String inString)
        {
            String equation = inString.Replace("==", "=");
            return equation.Replace("=", "==");
        }

        public static Int32 SearchForEndBackwards(String SearchMe, String inOperator, Int32 startLocation)
        {
            Int32 L;
            String subString;
            for (L = startLocation - 1; L >= 0; L--)
            {
                if (L + inOperator.Length > SearchMe.Length)
                {
                    //fail!
                }
                else
                {
                    subString = SearchMe.Substring(L, inOperator.Length);
                    if (inOperator == subString)
                    {
                        return L + inOperator.Length;
                    }
                }
            }
            return 0;
        }

        public static List<String> Split(String inString, String inOperator, Boolean removeEmptyEntries = false)
        {
            String[] seperators = new String[1];
            seperators[0] = inOperator;
            String[] strs;
            if (removeEmptyEntries == true)
            {
                strs = inString.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
            }
            else
            {
                strs = inString.Split(seperators, StringSplitOptions.None);
            }
            List<String> lOut = strs.ToList<String>();
            return lOut;
        }

        public static Boolean IsNumeric(String inString)
        {
            Double lDouble;
            return Double.TryParse(inString, out lDouble);
        }

        public static String Join(List<String> Strings, String Operator)
        {
            return String.Join(Operator, Strings.ToArray());
        }

        public static List<T> RemoveNulls<T>(List<T> inList)
        {
            List<T> lOut = new List<T>();
            Int32 L;
            for (L = 0; L < inList.Count; L++)
            {
                if (inList[L] != null)
                {
                    lOut.Add(inList[L]);
                }
            }
            return lOut;
        }

        public static String[] SyntaxNodesToStrings(SyntaxNode[] nodes)
        {
            return Functional.Maps.Map(nodes, x => x.ToString());
        }

        public static String AddDToNumber(String inString)
        {
            if (inString.Substring(inString.Length - 1, 1) != "d")
            {
                inString += "d";
            }
            return inString;
        }

        public static String RemoveDFromNumber(String inString)
        {
            if (inString.Substring(inString.Length - 1, 1) == "d")
            {
                inString = inString.Substring(0, inString.Length - 1);
            }
            return inString;
        }

        public static SyntaxNode AddDToNumber(SyntaxNode inString)
        {
            return Syntax.ParseExpression(AddDToNumber(inString.ToString()));
        }

        public static SyntaxNode RemoveDFromNumber(SyntaxNode inString)
        {
            return Syntax.ParseExpression(RemoveDFromNumber(inString.ToString()));
        }

        //public static TRoot ReplaceNodes<TRoot, TNode>(TRoot root, IEnumerable<TNode> oldNodes, Func<TNode, SyntaxNode> computeReplacementNode)
        //    where TRoot : SyntaxNode
        //    where TNode : SyntaxNode
        //{
        //    return root.ReplaceNodes(oldNodes, (oldNode, wth) => computeReplacementNode(oldNode));
        //}

        public static SyntaxNode ReplaceNodes(SyntaxNode root, List<SyntaxNode> oldNodes, Func<SyntaxNode, SyntaxNode> computeReplacementNode)
        {
            SyntaxNode result = root.ReplaceNodes(oldNodes, (oldNode, wth) => computeReplacementNode(oldNode));
            return result;
        }

        public static String AddDSuffixesToEquation(String inEquation)
        {
            SyntaxNode root = EquationToSyntaxNode(inEquation);
            List<SyntaxNode> numberBranches = NumberBranches(root);
            SyntaxNode alteredRoot = ReplaceNodes(root, numberBranches, AddDToNumber);
            return alteredRoot.ToString();
        }

        public static String RemoveDSuffixesFromEquation(String inEquation)
        {
            SyntaxNode root = EquationToSyntaxNode(inEquation);
            List<SyntaxNode> numberBranches = NumberBranches(root);
            SyntaxNode alteredRoot = ReplaceNodes(root, numberBranches, RemoveDFromNumber);
            return alteredRoot.ToString();
        }

        public static List<SyntaxNode> NumberBranches(SyntaxNode root)
        {
            List<SyntaxNode> branches = root.DescendantNodesAndSelf().ToList();
            var numberBranches = from n in branches
                                 where n.Kind == SyntaxKind.NumericLiteralExpression
                                 select n;
            return numberBranches.ToList();
        }

        public static Boolean HasChildren(SyntaxNode inNode)
        {
            List<SyntaxNode> children = inNode.ChildNodes().ToList();
            if (children.Count >0)
            {
                return true;
            }
            return false;
        }
    }
}
